Processing Stages (MI.ProcessingStages)
Processing Stages
(MI.ProcessingStages)
The Processing Stages object sets the rules that are applied during a specific stage of the overall transaction: When the client request is received, before the request is sent to the origin, and before the response is sent to the client.
The following processing stage rules are supported by Qwilt CDN:
- client-request: Defines actions to be taken upon receiving the client request. Currently this object can be used to:
- Influence the origin selection.
- Set conditions for rejecting or redirecting client requests based on header information (client request access).
- origin-request: Modifies the request to the origin by manipulating the URI or headers of the request received from the client.
- client-response: Modifies the client response by overriding the status code or manipulating the headers of the origin response.
For Processing Stage rules (MI.ProcessingStages), the inheritance logic applies to the entire set of rules as a single unit. That means:
- If any Processing Stage rule is configured at the host level, it completely overrides all Processing Stage rules from the site level.
- If any Processing Stage rule is configured at the path level, it completely overrides all Processing Stage rules from the host level.
For example, if the host configuration includes an On Client Request and an On Client Response rule, and the path configuration includes an On Origin Request rule, then only the On Origin Request rule is applied to the path. The host-level rules for Client Request and Client Response are not inherited by that path.
Example Structure
The following is an example illustrating the overall structure of the MI.ProcessingStages object when multiple stages and rules are configured. Note that each of the client-request
, origin-request
, and client-response
objects are nested within the generic-metadata-value
of the MI.ProcessingStages
object.
We'll describe the specific configurations for each stage in the following sections.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-request": [
{
"match": {
"expression": "req.h.user-agent ~= 'Mozilla'"
},
"stage-metadata": [
{
"generic-metadata": [
{
"generic-metadata-type": "MI.SourceMetadataExtended",
"generic-metadata-value": {
"sources": [
{
"protocol": "https/1.1",
"endpoints": [
"example.origin2.com"
]
}
]
}
}
]
}
]
},
{
"match": {
"expression": "req.h.MySecret != 'm1y2e3f4b5m6m7y9'"
},
"stage-metadata": [
{
"response-transform": {
"synthetic": {
"response-status": "403"
}
}
}
]
}
],
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"headers": {
"add": [
{
"name": "x-cdn-processed",
"value": "true",
"value-is-expression": false
}
]
}
}
}
]
}
],
"client-response": [
{
"stage-metadata": [
{
"response-transform": {
"headers": {
"add": [
{
"name": "served-by",
"value": "qwilt-cdn",
"value-is-expression": false
}
]
}
}
}
]
}
]
}
}
client-request
Rules in this stage are evaluated when the CDN receives a request from the client. They are primarily used for origin selection and client request access based on criteria defined in a match expression.
Rules are defined using match
conditions and stage metadata
.
Origin Selection
You can use the client-request
stage to direct certain client requests (e.g. based on user agent, headers, etc.) to an alternate origin. This is achieved by embedding an MI.SourceMetadataExtended
object within the generic-metadata
array inside stage-metadata
.
Use a MEL condition in the match
field to determine when this alternate origin should be used.
In this example, requests from a Mozilla user agent (the match condition) are directed to example.origin2.com
.
Note the two nodes nested under client-request
:
- The
MI.SourceMetadataExtended
object defines the origin configuration. In this example, a single origin host is configured. However, you could also configure a failover or round-robin origin type. - The
match
field contains the MEL expression that sets the condition for directing a request to the alternate origin. In this example, the condition is if the user-agent is Mozilla.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-request": [
{
"stage-metadata": [
{
"generic-metadata": [
{
"generic-metadata-type": "MI.SourceMetadataExtended",
"generic-metadata-value": {
"sources": [
{
"protocol": "https/1.1",
"endpoints": [
"example.origin2.com"
]
}
]
}
}
]
}
],
"match": {
"expression": "req.h.user-agent ~= 'Mozilla'"
}
}
]
}
}
Client Request Access
You can use the client-request
stage to set conditions for rejecting or redirecting incoming client requests based on criteria in a match expression. For example, to block specific referrers, or require a secret header.
This is achieved using the response-transform
object within stage-metadata
. The CDN generates a synthetic response directly to the client without contacting the origin.
Example 1: Reject a Request
To reject a request, set the desired HTTP status code (e.g., "403") using response-transform.synthetic.response-status
.
In this example, requests are rejected with a 403 Forbidden status if the MySecret
header does not match the expected value.
The match field contains the MEL expression that sets the condition for rejecting the request.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-request": [
{
"match": {
"expression": "req.h.MySecret != 'm1y2e3f4b5m6m7y9'"
},
"stage-metadata": [
{
"response-transform": {
"synthetic": {
"response-status": "403"
}
}
}
]
}
]
}
}
Example 2: Redirect a Request
Set the redirect status code (e.g., "301", "302") in response-transform.synthetic.response-status
and add a Location
header within response-transform.synthetic.headers
specifying the redirect target URL. The target URL can be constructed dynamically using MEL expressions by setting value-is-expression
to true
.
This example redirects requests from a specific referrer (https://example.com
) to https://the-other-server.com
, preserving the original path and query string.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-request": [
{
"match": {
"expression": "req.h.referer ~= 'https://example.com'"
},
"stage-metadata": [
{
"response-transform": {
"synthetic": {
"response-status": "301",
"headers": [
{
"name": "location",
"value": "'https://the-other-server.com' . req.uri.path . ((req.uri.query == '') ? '' : '?') . req.uri.query",
"value-is-expression": true
}
]
}
}
}
]
}
]
}
}
origin-request
This stage lets you modify the request before it is sent to the origin server. You can manipulate the request received from the client by modifying the URI value, or adding/replacing/deleting request headers. MEL expressions can be used to generate dynamic values for these fields, and to create match conditions.
These actions are defined within the request-transform
object inside stage-metadata
.
The origin-request
stage supports the following actions within request-transform
:
Action | Description |
---|---|
URI Rewrite | (uri , uri-is-expression ) Modifies the URI path and/or query string from the client before sending the request to the origin, often using a MEL expression. |
Add Header | (headers.add ) Adds the specified header/s and header value/s to the request, in addition to any same-name headers that may already be present. |
Replace Header | (headers.replace ) Replaces the header value for all instances of the header that are already present. If the header is not already in the request, this action adds the header and specified value to the request. |
Delete Header | (headers.delete ) Deletes all instances of the specified header/s from the request. |
Actions within a single origin-request rule are executed in the order in which they appear, so it is important to arrange them in a logical sequence.
The exception is header transform actions—delete header, replace header, and add header— which are always executed in the fixed order: delete, then replace, then add, regardless of their placement within the rule.
To control the order of header transforms differently, define them in separate rules and arrange the rules accordingly.
Example 1: Add a Request Header
The following configuration adds the x-cdn
header with the value qwilt
to every origin request.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"headers": {
"add": [
{
"value": "qwilt",
"name": "x-cdn",
"value-is-expression": false
}
]
}
}
}
]
}
]
}
}
Example 2: Replace a Header
Configure a replace
rule to replace any existing value if the header is already present, or to add the header and specified value if the header is not already present.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"headers": {
"replace": [
{
"value": "qwilt",
"name": "x-cdn"
}
]
}
}
}
]
}
]
}
}
Example 3: Delete a Header
Use delete
to delete a header from the origin request:
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"headers": {
"delete": [
"x-forwarded-for"
]
}
}
}
]
}
]
}
}
Example 4: Add Header Constructed Based on a MEL Expression
Instead of setting a static header value, you can add a value construction expression to the configuration. To do so, add the "value-is-expression" attribute and use the "value" attribute to add the MEL expression.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"headers": {
"add": [
{
"value": "<value construction expression>",
"name": "x-cdn",
"value-is-expression": true
}
]
}
}
}
]
}
]
}
}
Example 5: Add Header if Condition Defined by Match Expression is Met
To modify the origin request only under certain conditions, a match expression is added to the configuration:
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"headers": {
"add": [
{
"value": "qwilt",
"name": "x-cdn"
}
]
}
}
}
],
"match": {
"expression": "req.uri.query.foo == 'bar'"
}
}
]
}
}
Example 6: Rewrite the URI Path
To configure a URI manipulation, you set the MEL Expression in the uri
field.
This example uses URI manipulation to remove the first path segment. For example, /session123/video/file.mp4
will be changed to /video/file.mp4
.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"uri": "match_replace(req.uri.path, '^/[^/]+(/.*)$', '$1') . ((req.uri.query == '') ? '' : '?') . req.uri.query",
"uri-is-expression": true
}
}
]
}
]
}
}
Example 7: Remove all Query Parameters
This is how you would instruct the CDN to remove all the query parameters but preserve the path:
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"uri": "req.uri.path",
"uri-is-expression": true
}
}
]
}
]
}
}
Example 8: Remove Query Parameters and Add Prefix to URI
This example removes all the query parameters and prepends the URI with the string, /video
.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"uri": "'/video' . req.uri.path",
"uri-is-expression": true
}
}
]
}
]
}
}
client-response
This stage lets you modify the client response received from the origin before it is sent to the client. Modifications can include overriding the HTTP status code or adding/replacing/deleting response headers.
These actions are defined within the response-transform
object inside stage-metadata
.
MEL expressions can be used to generate dynamic values for these fields, and to create match conditions.
The client-response object supports the following actions within response-transform
:
Action | Description |
---|---|
Status Code Override | (response-status ) Sets the HTTP status code in the Client Response, overriding the status code received from the origin. |
Add Header | (headers.add ) Adds the specified header/s and header value/s to the response, in addition to any same-name headers that may already be present. |
Replace Header | (headers.replace ) Replaces the header value for all instances of the header that are already present. If the header is not already in the response, this action adds the header and specified value to the response. |
Delete Header | (headers.delete ) Deletes all instances of the specified header/s from the response. |
In addition, you can add a MEL expression to create a match condition.
Actions within a single client-response rule are executed in the order in which they appear, so it is important to arrange them in a logical sequence.
The exception is header transform actions—delete header, replace header, and add header— which are always executed in the fixed order: delete, then replace, then add, regardless of their placement within the rule.
To control the order of header transforms differently, define them in separate rules and arrange the rules accordingly.
Example 1: Add a Response Header
This example instructs the CDN to add the served-by
header with the value qwilt-cdn
to every client response.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-response": [
{
"stage-metadata": [
{
"response-transform": {
"headers": {
"add": [
{
"value": "qwilt-cdn",
"name": "served-by"
}
]
}
}
}
]
}
]
}
}
Note that this action defines a static value, "qwilt-cdn."
Example 2: Add a Dynamic Header
To set a dynamic header value with a MEL expression, add the value-is-expression
attribute and use the value
field to define the MEL expression:
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"response-transform": {
"headers": {
"add": [
{
"value": "<value construction expression>",
"name": "x-cdn",
"value-is-expression": true
}
]
}
}
}
]
}
]
}
}
Example 3: Replace Header
In this example, any instance of the x-cdn
header in the client response is assigned the value, qwilt
. If no instance of the header is found, the header is added to the response and assigned the value qwilt
.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"origin-request": [
{
"stage-metadata": [
{
"request-transform": {
"headers": {
"replace": [
{
"value": "qwilt",
"name": "x-cdn"
}
]
}
}
}
]
}
]
}
}
Example 4: Delete Header
This example is configured to delete the "server" header from the client response.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-response": [
{
"stage-metadata": [
{
"response-transform": {
"headers": {
"delete": [
"server"
]
}
}
}
]
}
]
}
}
Example 5: Set a Match Condition
To modify the client response only under certain conditions, add a match expression to the configuration.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-response": [
{
"stage-metadata": [
{
"response-transform": {
"headers": {
"add": [
{
"value": "qwilt",
"name": "served-by"
}
]
}
}
}
],
"match": {
"expression": "req.uri.query.foo == 'bar'"
}
}
]
}
}
Example 6: Override the Status Code
This example replaces the HTTP status code received from the origin with 200 OK
.
{
"generic-metadata-type": "MI.ProcessingStages",
"generic-metadata-value": {
"client-response": [
{
"stage-metadata": [
{
"response-transform": {
"response-status": "200"
}
}
]
}
]
}
}